﻿using System;
using System.Data;
using System.Collections.Generic;
using OnlineTestCOMMON;
using OnlineTestModel;
using OnlineTestDAL;
using System.Linq;
namespace OnlineTestBLL
{
	/// <summary>
	/// papers
	/// </summary>
	#region PapersBLL
	public class PapersBLL
	{
		PapersDAL dal=new PapersDAL();
		public PapersBLL()
		{}
		#region  Method

		/// <summary>
		/// 得到最大ID
		/// </summary>
		public int GetMaxId()
		{
			return dal.GetMaxId();
		}

		/// <summary>
		/// 是否存在该记录
		/// </summary>
		public bool Exists(int id)
		{
			return dal.Exists(id);
		}

		/// <summary>
		/// 增加一条数据
		/// </summary>
		public int  Add(Papers model)
		{
			return dal.Add(model);
		}

		/// <summary>
		/// 更新一条数据
		/// </summary>
		public bool Update(Papers model)
		{
			return dal.Update(model);
		}

	    /// <summary>
	    /// 试卷完成编辑
	    /// </summary>
	    public bool UpdateFinish(int id)
	    {
	        return dal.UpdateFinish(id);
	    }

	    /// <summary>
		/// 删除一条数据
		/// </summary>
		public bool Delete(int id)
		{
			
			return dal.Delete(id);
		}
		/// <summary>
		/// 删除一条数据
		/// </summary>
		public bool DeleteList(string idlist )
		{
			return dal.DeleteList(idlist );
		}

		/// <summary>
		/// 得到一个对象实体
		/// </summary>
		public Papers GetModel(int id)
		{
			
			return dal.GetModel(id);
		}

		#region 得到一个对象实体，从缓存中

		///// <summary>
		///// 得到一个对象实体，从缓存中
		///// </summary>
		//public Papers GetModelByCache(int id)
		//{

		//    string CacheKey = "papersModel-" + id;
		//    object objModel = Maticsoft.Common.DataCache.GetCache(CacheKey);
		//    if (objModel == null)
		//    {
		//        try
		//        {
		//            objModel = dal.GetModel(id);
		//            if (objModel != null)
		//            {
		//                int ModelCache = Maticsoft.Common.ConfigHelper.GetConfigInt("ModelCache");
		//                Maticsoft.Common.DataCache.SetCache(CacheKey, objModel, DateTime.Now.AddMinutes(ModelCache), TimeSpan.Zero);
		//            }
		//        }
		//        catch{}
		//    }
		//    return (Paper)objModel;
		//}

		#endregion


		/// <summary>
		/// 获得数据列表
		/// </summary>
		public DataSet GetList(string strWhere)
		{
			return dal.GetList(strWhere);
		}
		/// <summary>
		/// 获得前几行数据
		/// </summary>
		public DataSet GetList(int Top,string strWhere,string filedOrder)
		{
			return dal.GetList(Top,strWhere,filedOrder);
		}
		/// <summary>
		/// 获得数据列表
		/// </summary>
		public List<Papers> GetModelList(string strWhere)
		{
			DataSet ds = dal.GetList(strWhere);
			return DataTableToList(ds.Tables[0]);
		}
		/// <summary>
		/// 获得数据列表
		/// </summary>
		public List<Papers> DataTableToList(DataTable dt)
		{
			List<Papers> modelList = new List<Papers>();
			int rowsCount = dt.Rows.Count;
			if (rowsCount > 0)
			{
				Papers model;
				for (int n = 0; n < rowsCount; n++)
				{
					model = new Papers();
					if(dt.Rows[n]["id"]!=null && dt.Rows[n]["id"].ToString()!="")
					{
						model.Id=int.Parse(dt.Rows[n]["id"].ToString());
					}
					if(dt.Rows[n]["papername"]!=null && dt.Rows[n]["papername"].ToString()!="")
					{
					model.PaperName=dt.Rows[n]["papername"].ToString();
					}
					if(dt.Rows[n]["description"]!=null && dt.Rows[n]["description"].ToString()!="")
					{
					model.Description=dt.Rows[n]["description"].ToString();
					}
					if(dt.Rows[n]["createtime"]!=null && dt.Rows[n]["createtime"].ToString()!="")
					{
						model.CreateTime=DateTime.Parse(dt.Rows[n]["createtime"].ToString());
					}
					if(dt.Rows[n]["createid"]!=null && dt.Rows[n]["createid"].ToString()!="")
					{
						model.CreateId=int.Parse(dt.Rows[n]["createid"].ToString());
					}
					if(dt.Rows[n]["status"]!=null && dt.Rows[n]["status"].ToString()!="")
					{
					model.Status=dt.Rows[n]["status"].ToString();
					}
					if(dt.Rows[n]["starttime"]!=null && dt.Rows[n]["starttime"].ToString()!="")
					{
						model.StartTime=DateTime.Parse(dt.Rows[n]["starttime"].ToString());
					}
					if(dt.Rows[n]["endtime"]!=null && dt.Rows[n]["endtime"].ToString()!="")
					{
						model.EndTime=DateTime.Parse(dt.Rows[n]["endtime"].ToString());
					}
					if(dt.Rows[n]["classid"]!=null && dt.Rows[n]["classid"].ToString()!="")
					{
						model.ClassId=int.Parse(dt.Rows[n]["classid"].ToString());
					}
                    if (dt.Rows[n]["classid"] != null && dt.Rows[n]["classid"].ToString() != "")
                    {
                        model.ClassId = int.Parse(dt.Rows[n]["classid"].ToString());
                    }
                    if (dt.Rows[n]["isfinished"] != null && dt.Rows[n]["isfinished"].ToString() != "")
                    {
                        model.Isfinished = int.Parse(dt.Rows[n]["isfinished"].ToString());
                    }
                    if (dt.Rows[n]["editable"] != null && dt.Rows[n]["editable"].ToString() != "")
                    {
                        model.Editable = int.Parse(dt.Rows[n]["editable"].ToString());
                    }
					modelList.Add(model);
				}
			}
			return modelList;
		}

		/// <summary>
		/// 获得数据列表
		/// </summary>
		public DataSet GetAllList()
		{
			return GetList("");
		}

		/// <summary>
		/// 分页获取数据列表
		/// </summary>
		public int GetRecordCount(string strWhere)
		{
			return dal.GetRecordCount(strWhere);
		}
		/// <summary>
		/// 分页获取数据列表
		/// </summary>
		public DataSet GetListByPage(string strWhere, string orderby, int startIndex, int endIndex)
		{
			return dal.GetListByPage( strWhere,  orderby,  startIndex,  endIndex);
		}
		/// <summary>
		/// 分页获取数据列表
		/// </summary>
		//public DataSet GetList(int PageSize,int PageIndex,string strWhere)
		//{
			//return dal.GetList(PageSize,PageIndex,strWhere);
		//}

		#endregion  Method
		#region CreatePaper

		#endregion
	}
	 #endregion
	#region CreatePaper

	public class CreatePaper
	{
		/// <summary>
		/// 编号
		/// </summary>
		public double KPCoverage { get; set; }

		/// <summary>
		/// 适应度
		/// </summary>
		public double Difficulty { get; set; }
		public CreatePaper(double kpcoverage,double difficulty)
		{
			this.KPCoverage = kpcoverage;
			this.Difficulty = difficulty;
		}

	   
		/// <summary>
		/// 初始种群
		/// </summary>
		/// <param name="count">个体数量</param>
		/// <param name="paper">期望试卷</param>
		/// <param name="problemList">题库</param>
		/// <returns>初始种群</returns>
		public List<Unit> CSZQ(int count, PaperEX paper, List<QuestionEx> problemList)
		{
			List<Unit> unitList = new List<Unit>();
			int[] eachTypeCount = paper.EachTypeCount;
			Unit unit;
			Random rand = new Random();
			for (int i = 0; i < count; i++)
			{
				unit = new Unit();
				unit.Id = i + 1;
				unit.AdaptationDegree = 0.00;

				//总分限制，这块这个三重循环实在是够劲
				while (paper.TotalScore != unit.SumScore)
				{
					unit.ProblemList.Clear();

					//各题型题目数量限制
					for (int j = 0; j < eachTypeCount.Length; j++)
					{
						List<QuestionEx> oneTypeProblem = problemList
							.Where(o => o.Type == (j + 1))
							.Where(p => IsContain(paper, p))
							.ToList();
						QuestionEx temp = new QuestionEx();
						for (int k = 0; k < eachTypeCount[j]; k++)
						{
							//选择不重复的题目
							int index = rand.Next(0, oneTypeProblem.Count - k);
							unit.ProblemList.Add(oneTypeProblem[index]);
							temp = oneTypeProblem[oneTypeProblem.Count - 1 - k];
							oneTypeProblem[oneTypeProblem.Count - 1 - k] = oneTypeProblem[index];
							oneTypeProblem[index] = temp;
						}
					}
				}
				unitList.Add(unit);
			}

			//计算知识点覆盖率及适应度
			unitList = GetKPCoverage(unitList, paper);

			unitList = GetAdaptationDegree(unitList, paper, KPCoverage, Difficulty);

			return unitList;

		}
		/// <summary>
		/// 计算知识点覆盖率
		/// </summary>
		/// <param name="unitList">种群</param>
		/// <param name="paper">期望试卷</param>
		/// <returns>List</returns>
		public List<Unit> GetKPCoverage(List<Unit> unitList, PaperEX paper)
		{
			List<int> kp;
			for (int i = 0; i < unitList.Count; i++)
			{
				kp = new List<int>();
				unitList[i].ProblemList.ForEach(delegate(QuestionEx p)
				{
					kp.Add(p.Points);//注意add和addrange的区别
				});

				//个体所有题目知识点并集跟期望试卷知识点交集
				var common = kp.Intersect(paper.Points);
				unitList[i].KPCoverage = common.Count() * 1.00 / paper.Points.Count;
			}
			return unitList;
		}
		/// <summary>
		/// 计算种群适应度
		/// </summary>
		/// <param name="unitList">种群</param>
		/// <param name="paper">期望试卷</param>
		/// <param name="KPCoverage">知识点分布在适应度计算中所占权重</param>
		/// <param name="Difficulty">试卷难度系数在适应度计算中所占权重</param>
		/// <returns>List</returns>
		public List<Unit> GetAdaptationDegree(List<Unit> unitList, PaperEX paper, double KPCoverage, double Difficulty)
		{
			unitList = GetKPCoverage(unitList, paper);
			for (int i = 0; i < unitList.Count; i++)
			{
				unitList[i].AdaptationDegree = 1 - (1 - unitList[i].KPCoverage) * KPCoverage - Math.Abs(unitList[i].Difficulty - paper.Difficulty) * Difficulty;
			}
			return unitList;
		}
		/// <summary>
		/// 选择算子（自然选择）
		/// </summary>
		/// <param name="unitList">种群</param>
		/// <param name="count">选择次数</param>
		/// <returns>进入下一代的种群</returns>
		public List<Unit> SelectByNature(List<Unit> unitList, int count)
		{
			List<Unit> selectedUnitList = new List<Unit>();
			selectedUnitList.AddRange(unitList.OrderByDescending(u => u.AdaptationDegree).Take(count));//先排序再拿前10
			return selectedUnitList;

		}
		
		/// <summary>
		/// 交叉算子
		/// </summary>
		/// <param name="unitList">种群</param>
		/// <param name="count">交叉后产生的新种群个体数量</param>
		/// <param name="paper">期望试卷</param>
		/// <returns>List</returns>
		public List<Unit> Cross(List<Unit> unitList, int count, PaperEX paper)
		{
			List<Unit> crossedUnitList = new List<Unit>();
			Random rand = new Random();
			while (crossedUnitList.Count != count)
			{
				//随机选择两个个体
				int indexOne = rand.Next(0, unitList.Count);
				int indexTwo = rand.Next(0, unitList.Count);
				Unit unitOne;
				Unit unitTwo;
				if (indexOne != indexTwo)
				{
					unitOne = unitList[indexOne];
					unitTwo = unitList[indexTwo];

					//随机选择一个交叉位置
					int crossPosition = rand.Next(0, unitOne.ProblemCount - 2);

					//保证交叉的题目分数合相同
					int scoreOne = unitOne.ProblemList[crossPosition].Score + unitOne.ProblemList[crossPosition + 1].Score;
					int scoreTwo = unitTwo.ProblemList[crossPosition].Score + unitTwo.ProblemList[crossPosition + 1].Score;
					if (scoreOne == scoreTwo)
					{
						//两个新个体
						Unit unitNewOne = new Unit();
						unitNewOne.ProblemList.AddRange(unitOne.ProblemList);
						Unit unitNewTwo = new Unit();
						unitNewTwo.ProblemList.AddRange(unitTwo.ProblemList);

						//交换交叉位置后面两道题
						for (int i = crossPosition; i < crossPosition + 2; i++)
						{
							unitNewOne.ProblemList[i] = new QuestionEx(unitTwo.ProblemList[i]);
							unitNewTwo.ProblemList[i] = new QuestionEx(unitOne.ProblemList[i]);
						}

						//添加到新种群集合中
						unitNewOne.Id = crossedUnitList.Count;
						unitNewTwo.Id = unitNewOne.Id + 1;
						if (crossedUnitList.Count < count)
						{
							crossedUnitList.Add(unitNewOne);
						}
						if (crossedUnitList.Count < count)
						{
							crossedUnitList.Add(unitNewTwo);
						}

					}
				}

				//过滤重复个体
				crossedUnitList = crossedUnitList.Distinct(new ProblemComparer()).ToList();
			}

			//计算知识点覆盖率及适应度
			crossedUnitList = GetKPCoverage(crossedUnitList, paper);
			crossedUnitList = GetAdaptationDegree(crossedUnitList, paper, KPCoverage, Difficulty);

			return crossedUnitList;
		}
		public class ProblemComparer : IEqualityComparer<Unit>
		{
			public bool Equals(Unit x, Unit y)
			{
				bool result = true;
				for (int i = 0; i < x.ProblemList.Count; i++)
				{
					if (x.ProblemList[i].Id != y.ProblemList[i].Id)
					{
						result = false;
						break;
					}
				}
				return result;
			}
			public int GetHashCode(Unit obj)
			{
				return obj.ToString().GetHashCode();
			}
		}
		/// <summary>
		/// 变异算子
		/// </summary>
		/// <param name="unitList">种群</param>
		/// <param name="problemList">题库</param>
		/// <param name="paper">期望试卷</param>
		/// <returns>List</returns>
		public List<Unit> Change(List<Unit> unitList, List<QuestionEx> problemList, PaperEX paper)
		{
			Random rand = new Random();
			int index = 0;
			unitList.ForEach(delegate(Unit u)
			{
				//随机选择一道题
				index = rand.Next(0, u.ProblemList.Count);
				QuestionEx temp = u.ProblemList[index];

				//得到这道题的知识点
				QuestionEx problem = new QuestionEx();

			    if (paper.Points.Contains(temp.Points))//存在则修改
			    {
			        problem.Points = temp.Points;
			    }
			    else//不存在就随机一个
			    {
			        int i = rand.Next(0, paper.Points.Count);
			        problem.Points = paper.Points[i];
			    }


			    //从数据库中选择包含此题有效知识点的同类型同分数不同题号试题
				var otherDB = from a in problemList
							  where a.Points == problem.Points
							  select a;

				List<QuestionEx> smallDB = otherDB.Where(p => IsContain(paper, p)).Where(o => o.Type == temp.Type && o.Id != temp.Id).ToList();

				//从符合要求的试题中随机选一题替换
				if (smallDB.Count > 0)
				{
					int changeIndex = rand.Next(0, smallDB.Count);
					u.ProblemList[index] = smallDB[changeIndex];
				}
			});

			//计算知识点覆盖率跟适应度
			unitList = GetKPCoverage(unitList, paper);
			unitList = GetAdaptationDegree(unitList, paper, KPCoverage, Difficulty);
			return unitList;

		} /// <summary>
		/// 调用示例
		/// </summary>
		/// 
		public Unit Create(double expand,int choiceNum,int completionNum,int tofNum,int shortNum,List<int> pointsList,int choiceScore, int completionScore, int tofScore, int shortScore, int courseId)
		{
			//题库
			DB db = new DB(choiceScore,completionScore,tofScore,shortScore,courseId);

		   
			//期望试卷
			PaperEX paper = new PaperEX()
			{
				Id = 1,
				TotalScore = 100,
				Difficulty = 0.72,
				Points = pointsList,
				EachTypeCount = new[] { choiceNum, completionNum, tofNum, shortNum }
			};

			//迭代次数计数器
			int count = 1;

			
			//最大迭代次数
			int runCount = 20;

			//初始化种群
			List<Unit> unitList = CSZQ(20, paper, db.QuestionExDB);
			
			while (!IsEnd(unitList, expand))
			{
				if (count > runCount)
				{
					break;
				}

				//选择
				unitList = SelectByNature(unitList, 10);

				//交叉
				unitList = Cross(unitList, 20, paper);

				//是否可以结束（有符合要求试卷即可结束）
				if (IsEnd(unitList, expand))
				{
					break;
				}

				//变异
				unitList = Change(unitList, db.QuestionExDB, paper);
			    count++;
			}
			return ReturnResult(unitList, expand);//不论是否迭代成功，都应该返回一个Unit
		}
		#region 是否达到目标
		/// <summary>
		/// 是否达到目标
		/// </summary>
		/// <param name="unitList">种群</param>
		/// <param name="endcondition">结束条件（适应度要求）</param>
		/// <returns>bool</returns>
		public bool IsEnd(List<Unit> unitList, double endcondition)
		{
			if (unitList.Count > 0)
			{
				for (int i = 0; i < unitList.Count; i++)
				{
					if (unitList[i].AdaptationDegree >= endcondition)
					{
						return true;
					}
				}
			}
			return false;
		}
		#endregion

		#region 返回结果
		/// <summary>
		/// 返回结果
		/// </summary>
		/// <param name="unitList">种群</param>
		/// <param name="expand">期望适应度</param>
		public Unit ReturnResult(List<Unit> unitList, double expand)
		{
			return unitList.OrderByDescending(u => u.AdaptationDegree).First();
		}
		#endregion

		
		
		#region 题目知识点是否符合试卷要求
		/// <summary>
		/// 题目知识点是否符合试卷要求
		/// </summary>
		/// <param name="paper">期望试卷</param>
		/// <param name="problem">一首试题</param>
		/// <returns>bool</returns>
		private bool IsContain(PaperEX paper, QuestionEx problem)
		{

			if (paper.Points.Contains(problem.Points))
			{
				return true;
			}

			return false;
		}

		#endregion
	}
#endregion
#region DB
	public class DB
	{
		/// <summary>
		/// 题库
		/// </summary>
		public List<QuestionEx> QuestionExDB;

		public DB(int choiceScore,int completionScore,int tofScore,int shortScore,int courseId)
		{
			QuestionsBLL qb = new QuestionsBLL();
			QuestionExDB = qb.GetQuestionExList(courseId);
			QuestionEx qe;
			for (int i = 1; i < QuestionExDB.Count; i++)
			{
				;
				switch (QuestionExDB[i].Type)
				{
					case 1:
						QuestionExDB[i].Score = choiceScore;
						break;
					case 2:
						QuestionExDB[i].Score = completionScore;
						break;
					case 3:
						QuestionExDB[i].Score = tofScore;
						break;
					case 4:
						QuestionExDB[i].Score = shortScore;
						break;
				}

			}
		}

	}
#endregion
}

